#include "../include/ai_integration.h"
#include <sstream>
#include <algorithm>
#include <chrono>
#include <iostream>
#include <vector>
#ifdef _WIN32
#include <windows.h>
#include <winhttp.h>
#pragma comment(lib, "winhttp.lib")
#endif

// Explicitly check if HAVE_CURL is not defined or is 0
#if !defined(HAVE_CURL) || HAVE_CURL == 0
    #define HAVE_CURL_DISABLED
#endif

struct MemoryStruct {
    char *memory;
    size_t size;
};

static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) {
    size_t realsize = size * nmemb;
    struct MemoryStruct *mem = (struct MemoryStruct *)userp;
    
    char *ptr = (char*)realloc(mem->memory, mem->size + realsize + 1);
    if(ptr == NULL) {
        printf("not enough memory (realloc returned NULL)\n");
        return 0;
    }
    
    mem->memory = ptr;
    memcpy(&(mem->memory[mem->size]), contents, realsize);
    mem->size += realsize;
    mem->memory[mem->size] = 0;
    
    return realsize;
}

AIIntegration::AIIntegration() {
#ifndef HAVE_CURL_DISABLED
    curl_global_init(CURL_GLOBAL_DEFAULT);
#endif
    system_prompt_ = "You are an intelligent assistant, please provide accurate and useful answers to users.";
}

AIIntegration::~AIIntegration() {
#ifndef HAVE_CURL_DISABLED
    curl_global_cleanup();
#endif
}

bool AIIntegration::initialize(const std::string& api_key, const std::string& base_url) {
    api_key_ = api_key;
    base_url_ = base_url.empty() ? "https://api.deepseek.com/v1/chat/completions" : base_url;
    if (base_url_ == "https://api.deepseek.com" || base_url_ == "https://api.deepseek.com/") {
        base_url_ = "https://api.deepseek.com/v1/chat/completions";
    }
    return !api_key_.empty();
}

AIResponse AIIntegration::query(const std::string& message, const std::string& session_id) {
    AIResponse response;
    response.success = false;
    if (api_key_.empty()) {
        response.error_message = "AI service not initialized";
        return response;
    }
    
    // Get session history
    std::vector<std::string> history;
    if (!session_id.empty()) {
        auto it = session_histories_.find(session_id);
        if (it != session_histories_.end()) {
            history = it->second;
        }
    }
    
    // Build request JSON
    std::string json_body = buildRequestJson(message, history);
    
    // Send HTTP request
    std::string api_response = makeHttpPostRequest(base_url_, json_body);
    
    if (api_response.empty()) {
        response.content = generateMockResponse(message);
        response.success = true;
        return response;
    }
    
    // Parse response
    response = parseResponseJson(api_response);
    
    // If successful, update session history
    if (response.success && !session_id.empty()) {
        session_histories_[session_id].push_back("User: " + message);
        session_histories_[session_id].push_back("Assistant: " + response.content);
        
        // Limit history length
        if (session_histories_[session_id].size() > 20) {
            session_histories_[session_id].erase(session_histories_[session_id].begin(),
                                               session_histories_[session_id].begin() + 2);
        }
    }
    
    return response;
}

void AIIntegration::setSystemPrompt(const std::string& prompt) {
    system_prompt_ = prompt;
}

bool AIIntegration::clearSession(const std::string& session_id) {
    auto it = session_histories_.find(session_id);
    if (it != session_histories_.end()) {
        session_histories_.erase(it);
        return true;
    }
    return false;
}

std::vector<std::string> AIIntegration::getSessionHistory(const std::string& session_id) {
    auto it = session_histories_.find(session_id);
    if (it != session_histories_.end()) {
        return it->second;
    }
    return std::vector<std::string>();
}

std::string AIIntegration::makeHttpPostRequest(const std::string& url, const std::string& json_body) {
#ifdef HAVE_CURL_DISABLED
#ifdef _WIN32
    std::wstring wurl(url.begin(), url.end());
    URL_COMPONENTS uc = {0};
    uc.dwStructSize = sizeof(uc);
    wchar_t host[256] = {0};
    wchar_t path[1024] = {0};
    uc.lpszHostName = host; uc.dwHostNameLength = 256;
    uc.lpszUrlPath = path; uc.dwUrlPathLength = 1024;
    if (!WinHttpCrackUrl(wurl.c_str(), 0, 0, &uc)) {
        return std::string();
    }
    bool https = (uc.nScheme == INTERNET_SCHEME_HTTPS);
    HINTERNET hSession = WinHttpOpen(L"CPPSearch/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
    if (!hSession) return std::string();
    HINTERNET hConnect = WinHttpConnect(hSession, uc.lpszHostName, uc.nPort ? uc.nPort : (https ? 443 : 80), 0);
    if (!hConnect) { WinHttpCloseHandle(hSession); return std::string(); }
    HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"POST", uc.lpszUrlPath, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, https ? WINHTTP_FLAG_SECURE : 0);
    if (!hRequest) { WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession); return std::string(); }
    std::wstring headers = L"Content-Type: application/json\r\nAuthorization: Bearer " + std::wstring(api_key_.begin(), api_key_.end());
    BOOL sent = WinHttpSendRequest(hRequest, headers.c_str(), (DWORD)headers.length(), (LPVOID)json_body.data(), (DWORD)json_body.size(), (DWORD)json_body.size(), 0);
    if (!sent) { WinHttpCloseHandle(hRequest); WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession); return std::string(); }
    BOOL recvd = WinHttpReceiveResponse(hRequest, NULL);
    if (!recvd) { WinHttpCloseHandle(hRequest); WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession); return std::string(); }
    std::string result;
    DWORD dwSize = 0;
    do {
        DWORD dwDownloaded = 0;
        if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) break;
        if (dwSize == 0) break;
        std::vector<char> buffer(dwSize);
        if (!WinHttpReadData(hRequest, buffer.data(), dwSize, &dwDownloaded)) break;
        result.append(buffer.data(), buffer.data() + dwDownloaded);
    } while (dwSize > 0);
    WinHttpCloseHandle(hRequest);
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hSession);
    return result;
#else
    return std::string();
#endif
#else
    CURL *curl;
    CURLcode res;
    struct MemoryStruct chunk;
    chunk.memory = (char*)malloc(1);
    chunk.size = 0;
    curl = curl_easy_init();
    if(curl) {
        struct curl_slist *headers = NULL;
        headers = curl_slist_append(headers, "Content-Type: application/json");
        headers = curl_slist_append(headers, ("Authorization: Bearer " + api_key_).c_str());
        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_body.c_str());
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L);
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L);
        res = curl_easy_perform(curl);
        if(res != CURLE_OK) {
            fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
        }
        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
    }
    std::string result(chunk.memory);
    free(chunk.memory);
    return result;
#endif
}

std::string AIIntegration::buildRequestJson(const std::string& message, const std::vector<std::string>& history) {
    std::ostringstream json;
    json << "{\"model\":\"deepseek-chat\",\"messages\":[";
    
    // Add system prompt
    json << "{\"role\":\"system\",\"content\":\"" << escapeJson(system_prompt_) << "\"},";
    
    // Add conversation history
    for (const auto& item : history) {
        if (item.find("User: ") == 0) {
            json << "{\"role\":\"user\",\"content\":\"" << escapeJson(item.substr(6)) << "\"},";
        } else if (item.find("Assistant: ") == 0) {
            json << "{\"role\":\"assistant\",\"content\":\"" << escapeJson(item.substr(11)) << "\"},";
        }
    }
    
    // Add current message
    json << "{\"role\":\"user\",\"content\":\"" << escapeJson(message) << "\"}";
    
    json << "],\"temperature\":0.7,\"max_tokens\":2000}";
    
    return json.str();
}

AIResponse AIIntegration::parseResponseJson(const std::string& response) {
    AIResponse result;
    result.success = false;
    
    // Add debug logging
    
    // Check for errors first
    size_t error_start = response.find("\"error\":");
    if (error_start != std::string::npos) {
        size_t error_msg_start = response.find("\"message\":\"");
        if (error_msg_start != std::string::npos) {
            error_msg_start += 11; // length of "message":"            
            size_t error_msg_end = response.find("\"", error_msg_start);
            if (error_msg_end != std::string::npos) {
                result.error_message = response.substr(error_msg_start, error_msg_end - error_msg_start);
            } else {
                result.error_message = "Unknown API error";
            }
        } else {
            result.error_message = "API call error";
        }
        std::cout << "[ERROR] DeepSeek API error: " << result.error_message << std::endl;
        result.content = "Sorry, AI service returned an error: " + result.error_message;
        result.success = true; // Still return success to frontend, but with error message
        return result;
    }
    
    // Improved JSON parsing for content
    size_t content_start = response.find("\"content\":\"");
    if (content_start != std::string::npos) {
        content_start += 11; // length of "content":"        
        // Find the matching closing quote, considering escaped quotes
        int quote_count = 1;
        size_t content_end = content_start;
        bool in_escape = false;
        
        for (; content_end < response.length(); content_end++) {
            char c = response[content_end];
            
            if (in_escape) {
                in_escape = false;
            } else if (c == '\\') {
                in_escape = true;
            } else if (c == '"') {
                quote_count++;
                if (quote_count == 2) {
                    break;
                }
            }
        }
        
        if (content_end != response.length()) {
            result.content = response.substr(content_start, content_end - content_start);
            result.success = true;
            
            // Unescape the content
            size_t pos = 0;
            while ((pos = result.content.find('\\', pos)) != std::string::npos) {
                if (pos + 1 < result.content.length()) {
                    char next_char = result.content[pos + 1];
                    switch (next_char) {
                        case '"':
                        case '\\':
                            result.content.erase(pos, 1);
                            pos++;
                            break;
                        case 'n':
                            result.content.replace(pos, 2, "\n");
                            pos++;
                            break;
                        case 'r':
                            result.content.replace(pos, 2, "\r");
                            pos++;
                            break;
                        case 't':
                            result.content.replace(pos, 2, "\t");
                            pos++;
                            break;
                        default:
                            pos += 2;
                            break;
                    }
                } else {
                    break;
                }
            }
        }
    }
    
    // If parsing fails, return default response
    if (!result.success) {
        std::cout << "[ERROR] Failed to parse AI response" << std::endl;
        result.content = generateMockResponse("");
        result.success = true;
    }
    
    return result;
}

std::string AIIntegration::escapeJson(const std::string& str) {
    std::string result;
    for (char c : str) {
        switch (c) {
            case '"': result += "\\\""; break;
            case '\\': result += "\\\\"; break;
            case '\n': result += "\\n"; break;
            case '\r': result += "\\r"; break;
            case '\t': result += "\\t"; break;
            default: result += c; break;
        }
    }
    return result;
}

std::string AIIntegration::generateMockResponse(const std::string& query) const {
    // Simple mock AI response, generating related answers based on query keywords
    std::string lowerQuery = query;
    std::transform(lowerQuery.begin(), lowerQuery.end(), lowerQuery.begin(), ::tolower);
    
    if (lowerQuery.find("hello") != std::string::npos || lowerQuery.find("ni hao") != std::string::npos) {
        return "Hello! I am an AI assistant, happy to serve you. How can I help you today?";
    } else if (lowerQuery.find("search") != std::string::npos || lowerQuery.find("sousuo") != std::string::npos) {
        return "I can help you search for relevant information. Please tell me what content you want to search for, and I will do my best to provide you with accurate answers.";
    } else if (lowerQuery.find("help") != std::string::npos || lowerQuery.find("bangzhu") != std::string::npos) {
        return "I am your AI assistant, I can help you answer questions, provide information and perform searches. You can directly ask me any questions.";
    } else if (lowerQuery.find("tianqi") != std::string::npos || lowerQuery.find("weather") != std::string::npos) {
        return "Sorry, I currently cannot get real-time weather information. I recommend checking professional weather apps or websites for the latest weather forecasts.";
    } else if (lowerQuery.find("shijian") != std::string::npos || lowerQuery.find("time") != std::string::npos) {
        auto now = std::chrono::system_clock::now();
        auto time_t = std::chrono::system_clock::to_time_t(now);
        std::string timeStr = std::ctime(&time_t);
        return "Current time: " + timeStr.substr(0, timeStr.length() - 1);
    } else {
        return "Thank you for your question! This is a simulated AI response. In a real environment, I would connect to the DeepSeek API to provide you with more accurate and detailed answers. The system is currently running in demo mode.";
    }
}
